# == Schema Information
# Schema version: 33
#
# Table name: amistades
#
#  id         :integer(11)   not null, primary key
#  amigo_id   :integer(11)   
#  usuario_id :integer(11)   
#  created_at :datetime      
#  updated_at :datetime      
#  motivo     :text          
#  state      :string(255)   
#  invitado   :boolean(1)    
#

class Amistad < ActiveRecord::Base
  belongs_to :usuario
  belongs_to :amigo, :class_name => "Usuario", :foreign_key => :amigo_id
  after_update :crea_evento_amistad_aceptado_rechazado, :crea_evento_amistad_pendiente
  after_create :crea_evento_amistad_pendiente
  validates_presence_of :usuario_id, :amigo_id
  
  acts_as_state_machine :initial => :pendiente  
  state :pendiente  
  state :aceptado  
  state :rechazado  
  state :molestado

  event :aceptar do  
    transitions :from => :pendiente, :to => :aceptado
  end
   
  event :rechazar do  
    transitions :from => :pendiente, :to => :rechazado
    transitions :from => :aceptado, :to => :rechazado
  end
  
  event :molestar do
    transitions :from => :pendiente, :to => :molestado
  end
  
  event :pedir do
    transitions :from => :rechazado, :to => :pendiente
  end
  
  # ¿ Existe la amistad ?
  def self.existe?(usuario, amigo)
    not find_by_usuario_id_and_amigo_id(usuario, amigo).nil?
  end
  
  # Usuario le hace una peticion de amistad a amigo
  def self.peticion(usuario, amigo)
    if !(usuario == amigo || Amistad.existe?(usuario, amigo))
      transaction do
        create(:usuario => usuario, :amigo => amigo)
        create(:usuario => amigo, :amigo => usuario, :invitado => true)
      end
    elsif !(usuario == amigo) && Amistad.existe?(usuario, amigo)
      transaction do
        pedir_por_un_lado(amigo, usuario, true)
        pedir_por_un_lado(usuario, amigo, false)
      end
    end
    
  end

  # Amigo acepta a un usuario
  def self.aceptar(amigo, usuario)
    transaction do
      aceptar_por_un_lado(amigo, usuario)
      aceptar_por_un_lado(usuario, amigo)
    end
  end

  # Amigo rechaza a usuario
  def self.rechazar(amigo, usuario)
    transaction do
      rechazar_por_un_lado(amigo, usuario, "r")
      rechazar_por_un_lado(usuario, amigo, "i")
    end
  end
  
  # Amigo es molestado por usuario
  def self.molestar(amigo, usuario)
    transaction do
      if Amistad.invitado?(amigo, usuario)
        rechazar_por_un_lado(usuario, amigo, "r")
        molestar_por_un_lado(amigo, usuario)
      end
    end
  end
  
  # ¿ Es amigo el que ha sido invitado por usuario ?
  def self.invitado?(amigo, usuario)
    return find_by_usuario_id_and_amigo_id(amigo, usuario).invitado
  end 
  
private
  # Acepta una relacion en una dirección
  def self.aceptar_por_un_lado(usuario, amigo)
    amistad = find_by_usuario_id_and_amigo_id(usuario, amigo)
    amistad.aceptar!
    
    Recordatorio.find_or_create_by_usuario_id_and_amigo_id(usuario.id, amigo.id)
  end

  # Rechaza una relacion en una dirección
  def self.rechazar_por_un_lado(usuario, amigo, tipo)
    amistad = find_by_usuario_id_and_amigo_id(usuario, amigo)
    Evento.create(:usuario => usuario, :amigo_id => amigo.id, :tipo => "an-rechazado#{tipo}")
    amistad.rechazar!
    
    if (recordatorio = Recordatorio.find_by_usuario_id_and_amigo_id(usuario,amigo))
      recordatorio.destroy
    end
  end

  # Relación molesta en una dirección
  def self.molestar_por_un_lado(usuario, amigo)
    amistad = find_by_usuario_id_and_amigo_id(usuario, amigo)
    amistad.molestar!
  end

  # Petición de relación en una dirección
  def self.pedir_por_un_lado(usuario, amigo, invitado)
    amistad = find_by_usuario_id_and_amigo_id(usuario, amigo)
    amistad.invitado = invitado
    amistad.pedir!
  end

protected
  ## Callbacks ##
  def crea_evento_amistad_aceptado_rechazado
    if state == "aceptado"
      Evento.create(:usuario => amigo, :amigo_id => self.usuario.id, :tipo => "an-#{state}") if invitado
    end    
  end

  def crea_evento_amistad_pendiente
    Evento.create(:usuario => amigo, :amigo_id => self.usuario.id, :tipo => "an-pendiente") if state == "pendiente" and !invitado
  end
  ## /Callbacks ##

  # Email periódico para recordar las fechas importantes de los amigos.
  def self.recordar_fecha_importante 
    envios = {}

    Celebracion.find(:all, :conditions => ["date_format(fecha + INTERVAL 2 DAY , \"%e\") = ? AND date_format(fecha + INTERVAL 2 DAY, \"%c\") = ?", (Time.now + 2.days).day, (Time.now + 2.days).month]).each do |celebracion| 
      Recordatorio.find_all_by_usuario_id(celebracion.usuario).each do |recordatorio| 
        envios[recordatorio.amigo_id] = [] if envios[recordatorio.amigo_id].blank?
        envios[recordatorio.amigo_id] << celebracion
      end 
    end

    envios.each do |amigo_id, celebraciones|
      AmistadMailer.deliver_recordatorio_email(amigo_id, celebraciones)
    end
  end
end
